#include "stdafx.h"
#include "net/HTTPSessionFactory.hpp"
#include "net/HTTPSessionInstantiator.hpp"

#include "stdlib/exception.hpp"
using namespace JHCPP::stdlib::jhException;
#include "designpattern/singletonholder.hpp"
using JHCPP::designpattern::TSingletonHolder;


NET_NAMESPACE_BEGIN

CHTTPSessionFactory::CHTTPSessionFactory() : m_proxyPort(0)
{
}

CHTTPSessionFactory::CHTTPSessionFactory(const std::string& proxyHost, UInt16 proxyPort)
	: m_proxyHost(proxyHost), m_proxyPort(proxyPort)
{
}

CHTTPSessionFactory::~CHTTPSessionFactory()
{
	for (Instantiators::iterator it = m_instantiators.begin(); it != m_instantiators.end(); ++it)
	{
		delete it->second.pIn;
	}
}

void CHTTPSessionFactory::registerProtocol(const std::string& protocol, CHTTPSessionInstantiator* pSessionInstantiator)
{
	jh_assert_dbg(pSessionInstantiator);

	CMutex::ScopedLock lock(m_mutex);
	std::pair<Instantiators::iterator, bool> tmp = m_instantiators.insert(make_pair(protocol, InstantiatorInfo(pSessionInstantiator)));
	if (!tmp.second) 
	{
		++tmp.first->second.cnt;
		delete pSessionInstantiator;
	}
}

void CHTTPSessionFactory::unregisterProtocol(const std::string& protocol)
{
	CMutex::ScopedLock lock(m_mutex);

	Instantiators::iterator it = m_instantiators.find(protocol);
	if (it != m_instantiators.end())
	{
		if (it->second.cnt == 1)
		{
			delete it->second.pIn;
			m_instantiators.erase(it);
		}
		else --it->second.cnt;
	}
	else throw NotFoundException("No HTTPSessionInstantiator registered for", protocol);
}

bool CHTTPSessionFactory::supportsProtocol(const std::string& protocol)
{
	CMutex::ScopedLock lock(m_mutex);

	Instantiators::iterator it = m_instantiators.find(protocol);
	return it != m_instantiators.end();
}

CHTTPClientSession* CHTTPSessionFactory::createClientSession(const CURI& uri)
{
	CMutex::ScopedLock lock(m_mutex);

	if (uri.isRelative()) throw UnknownURISchemeException("Relative URIs are not supported by HTTPSessionFactory.");

	Instantiators::iterator it = m_instantiators.find(uri.getScheme());
	if (it != m_instantiators.end())
	{
		it->second.pIn->setProxy(m_proxyHost, m_proxyPort);
		it->second.pIn->setProxyCredentials(m_proxyUsername, m_proxyPassword);
		return it->second.pIn->createClientSession(uri);
	}
	else throw UnknownURISchemeException(uri.getScheme());
}

void CHTTPSessionFactory::setProxy(const std::string& host, UInt16 port)
{
	CMutex::ScopedLock lock(m_mutex);

	m_proxyHost = host;
	m_proxyPort = port;
}

void CHTTPSessionFactory::setProxyCredentials(const std::string& username, const std::string& password)
{
	CMutex::ScopedLock lock(m_mutex);

	m_proxyUsername = username;
	m_proxyPassword = password;
}


TSingletonHolder<CHTTPSessionFactory> singleton;

CHTTPSessionFactory& CHTTPSessionFactory::defaultFactory()
{
	return *singleton.get();
}

CHTTPSessionFactory::InstantiatorInfo::InstantiatorInfo(CHTTPSessionInstantiator* pInst): pIn(pInst), cnt(1)
{
	jh_check_ptr (pIn);
}

const std::string& CHTTPSessionFactory::proxyHost() const
{
	return m_proxyHost;
}

UInt16 CHTTPSessionFactory::proxyPort() const
{
	return m_proxyPort;
}

const std::string& CHTTPSessionFactory::proxyUsername() const
{
	return m_proxyUsername;
}

const std::string& CHTTPSessionFactory::proxyPassword() const
{
	return m_proxyPassword;
}

NET_NAMESPACE_END
